using System;
using System.Linq;
using System.Linq.Expressions;

public class AA {
    private static Expression guard(Expression suspect, Expression nullExpr, Expression nonNullExpr) {
        return
            Expression.Condition(
                Expression.Equal(
                    Expression.Constant(null),
                    aar(suspect)),
                nullExpr,
                nonNullExpr);
    }
    private static Expression nullExpr(Type t) {
        return
            Expression.TypeAs(
                Expression.Constant(null),
                t);
    }
    private static Expression guard(Expression suspect, Expression nonNullExpr) {
        return
            guard(
                suspect,
                nullExpr(nonNullExpr.Type),
                nonNullExpr);
    }
    private static Expression aar(Expression e) {
        var me = e as MemberExpression;
        if (me != null) {
            return
                guard(me.Expression, me);
        }
        var l = e as LambdaExpression;
        if (l != null) {
            return
                Expression.Lambda(
                    guard(
                        l.Body,
                        l.Body),
                    Enumerable.Select(
                        l.Parameters,
                        p => p).ToArray());
        }
        var ie = e as InvocationExpression;
        if (ie != null) {
            var args =               
                Enumerable.Select(
                    ie.Arguments,
                    (arg, i) => Expression.Parameter(arg.Type, String.Format("arg{0}", i))).ToArray();
            return
                Expression.Invoke(
                    guard(
                        ie.Expression,
                        Expression.Lambda(
                            nullExpr(ie.Expression.Type),
                            args),
                        Expression.Lambda(
                            ie.Expression,
                            args)),
                    Enumerable.Select(
                        ie.Arguments,
                        arg => aar(arg)));
        }
        return e;
    }
    public static T Andand<T>(Expression<Func<T>> f) {
        try {
            f = (Expression<Func<T>>)aar(f);
            return f.Compile()();
        }
        catch (Exception e) {
            throw new Exception(String.Format("trouble with {0}", f), e);
        }
    }
}
